#include "Base/Buffer.h"
#include <cstring>
#include <cassert>

namespace toym
{

Buffer::Buffer(std::size_t sz)
    : m_buf(sz > 16 ? sz : 16),
      m_readStart(s_defaultPrependSize),
      m_readEnd(m_readStart)
{}

void Buffer::append(const char* msg, std::size_t sz) {
    if (m_buf.size() - m_readEnd > sz) {
        // 后面的空间足够，直接在后面添加数据
        std::memmove(curEndAddr(), msg, sz);
        m_readEnd += sz;
    } else {
        std::size_t originSize = size();
        // 后面的空间不够，
        if (originSize >= s_defaultPrependSize + size() + sz) {
            // 但加上前面的空间，足够装得下数据和prepend的空间
            std::memmove(defaultStartAddr(), curStartAddr(), originSize);
            std::memmove(m_buf.data() + s_defaultPrependSize + originSize, msg, sz);
            m_readStart = s_defaultPrependSize;
            m_readEnd = m_readStart + originSize + sz;
        } else {
            // 加上前面的空间也不够，重新分配内存
            std::vector<char> newBuf(getSize(m_buf.size(), s_defaultPrependSize + originSize + sz));
            std::memmove(newBuf.data() + s_defaultPrependSize, curStartAddr(), originSize);
            std::memmove(newBuf.data() + s_defaultPrependSize + originSize, msg, sz);
            m_buf.swap(newBuf);
            m_readStart = s_defaultPrependSize;
            m_readEnd = m_readStart + originSize + sz;
        }
    }
}

void Buffer::append(const std::string& msg) {
    append(msg.c_str(), msg.size());
}

void Buffer::prepend(const char* msg, std::size_t sz) {
    if (m_readStart >= sz) {
        // 前面的空间足够
        std::memmove(m_buf.data() + m_readStart - sz, msg, sz);
        m_readStart -= sz;
    } else {
        // 前面的空间不够
        std::size_t originSize = size();
        if (m_buf.size() > s_defaultPrependSize + sz + originSize) {
            // 后面的空间足够 添加空间和留空间
            std::memmove(m_buf.data() + s_defaultPrependSize + sz, curStartAddr(), originSize);
            std::memmove(defaultStartAddr(), msg, sz);
            m_readStart = s_defaultPrependSize;
            m_readEnd = m_readStart + sz + originSize;
        } else {
            // 后面的空间也不足
            std::vector<char> newBuf(getSize(m_buf.size(), s_defaultPrependSize + sz + originSize));
            std::memmove(newBuf.data() + s_defaultPrependSize, msg, sz);
            std::memmove(newBuf.data() + s_defaultPrependSize + sz, curStartAddr(), originSize);
            m_buf.swap(newBuf);
            m_readStart = s_defaultPrependSize;
            m_readEnd = m_readStart + sz + originSize;
        }
    }
}

void Buffer::prepend(const std::string& msg) {
    prepend(msg.c_str(), msg.size());
}

void Buffer::read(std::size_t sz) {
    assert(sz <= size());
    m_readStart += sz;
    if (m_readStart == m_readEnd) {
        m_readStart = m_readEnd = s_defaultPrependSize;
    }
}

std::string Buffer::readAsString() {
    std::string ret(curStartAddr(), size());
    readAll();
    return ret;
}





} // namespace toym
